﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data.Linq;
using Acms.SqlDal;

namespace Acms.Bll
{
    public class EmailActivationCode : BaseItem
    {

        private EmailActivationCode() : base() { SetActivationCode(); }
        private EmailActivationCode(Hashtable table) : base(table) { }
        private EmailActivationCode(Hashtable table, List<EmailActivationCode> collection) : base(table, collection) { }

        private static void ValidateUnique(int userId, string emailAddress,int siteId)
        {
            if (userId > 0)
            {
                var user = User.GetByEmailAddress(emailAddress, siteId);
                if (user != null && user.Id != userId)
                {
                    throw new Exceptions.DuplicateEmailException(string.Format("Email '{0}' already exists on this site", emailAddress));
                }
            }
        }

        public static EmailActivationCode CreateInstance(int userId, string emailAddress, int siteId)
        {
            ValidateUnique(userId, emailAddress, siteId);
            return new EmailActivationCode()
            {
                UserId = userId,
                EmailAddress = emailAddress,
            };
        }

        public static EmailActivationCode CreateInstance(User user, string emailAddress, int siteId)
        {
            ValidateUnique(user.Id, emailAddress, siteId);
            return new EmailActivationCode()
            {
                UserId = user.Id,
                _User = user,
                EmailAddress = emailAddress,
            };
        }

        protected override Acms.SqlDal.Base CreateDal()
        {
            return new SqlDal.EmailActivationCode();
        }

        protected override void Load(System.Collections.Hashtable table)
        {
            Id = (int)table[SqlDal.EmailActivationCode.Fields.Id];
            UserId = (int)table[SqlDal.EmailActivationCode.Fields.UserId];
            Code = (string)table[SqlDal.EmailActivationCode.Fields.Code];
            EmailAddress = (string)table[SqlDal.EmailActivationCode.Fields.EmailAddress];
            Activated = (DateTime?)table[SqlDal.EmailActivationCode.Fields.Activated];
            Created = (DateTime)table[SqlDal.EmailActivationCode.Fields.Created];
        }

        public int Id { get; protected set; }
        public int UserId { get; protected set; }
        public string Code { get; protected set; }
        public string EmailAddress { get; protected set; }
        public DateTime? Activated { get; internal set; }
        public DateTime Created { get; protected set; }

        private User _User;
        public User User
        {
            get
            {
                if (_User == null && UserId > 0)
                {
                    _User = User.GetById(UserId);
                }
                return _User;
            }
        }

        private void SetActivationCode()
        {
            char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
            Random rnd = new Random();
            Code = string.Format("{0}{1}{2}{3}", chars[rnd.Next(0, chars.Length)], rnd.Next(0, 1000), chars[rnd.Next(0, chars.Length)], rnd.Next(0, 1000));
            if (Code.Length > 10)
                Code = Code.Substring(0, 10);

        }

        private static EmailActivationCode Get(Hashtable table)
        {
            return table != null ? new EmailActivationCode(table) : null;
        }

        private static List<EmailActivationCode> Get(Hashtable[] tables)
        {
            if (tables != null)
            {
                List<EmailActivationCode> tmp = new List<EmailActivationCode>();
                foreach (var table in tables)
                {
                    tmp.Add(new EmailActivationCode(table, tmp));
                }
                return tmp;
            }
            else
            {
                return null;
            }
        }

        public static EmailActivationCode GetById(int id)
        {
            return Get(new SqlDal.EmailActivationCode().GetById(id));
        }

        public static EmailActivationCode GetByCodeAndSiteId(string code, int siteId)
        {
            return Get(new SqlDal.EmailActivationCode().GetByCodeAndSiteId(code, siteId));
        }

        public static List<EmailActivationCode> GetAllByUserId(int userId)
        {
            return Get(new SqlDal.EmailActivationCode().GetAllByUserId(userId));
        }

        internal static EmailActivationCode GetByUserIdAndCode(int userId, string code)
        {
            return Get(new SqlDal.EmailActivationCode().GetByUserIdAndCode(userId, code));
        }

        public static List<EmailActivationCode> GetAllByUserIdAndEmail(int userId, string email)
        {
            return Get(new SqlDal.EmailActivationCode().GetAllByUserIdAndEmail(userId, email));
        }

        public new void Update()
        {
            if (IsNewRecord)
            {
                Created = GetCreatedDate();
            }
            base.Update();
        }

        private DateTime GetCreatedDate()
        {
            var tmp = DateTime.Now;
            return new DateTime(tmp.Year, tmp.Month, tmp.Day, tmp.Hour, tmp.Minute, tmp.Second, 0);
        }

        protected override object SaveChanges(ref object concurencyId, Base dal)
        {
            int idOut = this.Id;
            ((SqlDal.EmailActivationCode)dal).Update(ref idOut, UserId, Code, EmailAddress, Activated, Created, ref concurencyId);
            Id = idOut;
            return idOut;
        }

        public new void Delete()
        {
            base.Delete();
        }

        protected override void DeleteRecord(object concurencyId, Acms.SqlDal.Base dal)
        {
            ((SqlDal.EmailActivationCode)dal).Delete(Id, concurencyId);
        }

        public void SetAsActivated()
        {
            Activated = DateTime.Now;
        }

        public void Send(string filePath, string siteRoot, string authenticateUrl)
        {
            if (User == null)
            {
                throw new ApplicationException("Invalid user.");
            }
            Email email = Email.CreateInstance(User, this.EmailAddress, filePath);
            StringBuilder tmpActivationUrl = new StringBuilder();
            if (!siteRoot.Contains("://"))
            {
                tmpActivationUrl.Append("http://");
            }
            tmpActivationUrl.Append(siteRoot);
            if (!siteRoot.EndsWith("/"))
            {
                tmpActivationUrl.Append("/");
            }
            if (authenticateUrl.StartsWith("~/"))
            {
                tmpActivationUrl.Append(authenticateUrl.Substring(2));
            }
            else if (authenticateUrl.StartsWith("/"))
            {
                tmpActivationUrl.Append(authenticateUrl.Substring(1));
            }
            else
            {
                tmpActivationUrl.Append(authenticateUrl);
            }
            if (!authenticateUrl.Contains("?"))
            {
                tmpActivationUrl.Append("?");
            }
            else
            {
                tmpActivationUrl.Append("&");
            }
            tmpActivationUrl.AppendFormat("Code={0}", Code);
            email.Format("ActivationUrl", tmpActivationUrl.ToString());
            email.Send();
        }
    }
}
